package com.kasax.plugin.app.transform

import com.android.build.api.transform.*
import com.android.build.gradle.internal.pipeline.TransformManager
import com.android.utils.FileUtils
import com.kasax.plugin.app.LogUtils
import com.kasax.plugin.app.visitor.clickclass.ClickClassVisitor
import org.gradle.api.Project
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter

/**
 * 事件点击日志注入插桩
 * https://juejin.cn/post/6945380865404829703?
 */
class ClickLogInjectTransform extends Transform {
    final String TAG = "ClickLoginInjectTransform"


    Project project

    ClickLogInjectTransform(Project proj) {
        this.project = proj
    }

    // 设置我们自定义的Transform对应的Task名称
    // 类似：transformClassesWithPreDexForXXX
    // 这里应该是：transformClassesWithInjectTransformForxxx
    @Override
    String getName() {
        return "ClickLoginInjectTransform"
    }


    @Override
    Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_CLASS
    }

    @Override
    Set<? super QualifiedContent.Scope> getScopes() {
        return TransformManager.SCOPE_FULL_PROJECT
    }

    @Override
    boolean isIncremental() {
        return false
    }

    // inputs是传过来的输入流，有两种格式：jar和目录格式
    // outputProvider 获取输出目录，将修改的文件复制到输出目录，必须执行
//    @Override
//    void transform(Context context, Collection<TransformInput> inputs, Collection<TransformInput> referencedInputs, TransformOutputProvider outputProvider, boolean isIncremental) throws IOException, TransformException, InterruptedException {
//        LogUtils.d(TAG, "------------ ------------   transform 开始  ------------ ------------  ")
//
//
//        LogUtils.d(TAG, "------------ ------------  transform 结束  ------------ ------------  ")
//    }
    @Override
    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
        LogUtils.d(TAG, "------------ ------------   transform 开始  ------------ ------------  ")
        // 获取输入项进行遍历
        def transformInputs = transformInvocation.inputs
        // 获取输出目录
        def transformOutputProvider = transformInvocation.outputProvider
        transformInputs.each { TransformInput transformInput ->
            // 遍历Jar包
            LogUtils.d(TAG, "handle jarInputs")
            transformInput.jarInputs.each {
                JarInput jarInput ->
                    LogUtils.d(TAG, "jarInput: $jarInput")
                    // 使用jarFile解压
//                    def enmueration = new JarFile(jarInput.file).entries()
//                    while (enmueration.hasMoreElements()) {
//                        // 获取jar里面的内容
//                        def entry = enmueration.nextElement()
//                        LogUtils.d(TAG, "jarInput file: ${entry.name}")
//                    }
                    //直接将 jar 包 copy 到输出目录
                    File dest = transformOutputProvider.getContentLocation(
                            jarInput.name,
                            jarInput.contentTypes,
                            jarInput.scopes,
                            Format.JAR
                    )

                    File sourceFile = jarInput.file
                    String sourceFilePath = sourceFile.absolutePath
                    String destFilePath = dest.absolutePath
                    LogUtils.d(TAG, "copyJar FilesourceJarFile: $sourceFilePath , destFilePath: $destFilePath")
                    FileUtils.copyFile(sourceFile, dest)
            }

            LogUtils.d(TAG, "handle directoryInputs")
            // 遍历目录
            transformInput.directoryInputs.each { DirectoryInput directoryInput ->
                LogUtils.d(TAG, "directoryInput: $directoryInput")
                // 获取目录里面的class文件
                directoryInput.file.eachFileRecurse { File file ->
                    LogUtils.d(TAG, "directoryInput file: ${file.name}")
                    if (file.absolutePath.endsWith(".class")) {
                        // 对于class文件进行读取解析
                        def classReader = new ClassReader(file.bytes)
                        // 将class文件内容写入到ClassWriter中
                        def classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS)
                        // 使用ClickClassVisitor去读取内容
                        def classVisitor = new ClickClassVisitor(classWriter)
                        // 开始读取
                        classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES)
                        // 获取修改后的内容
                        def bytes = classWriter.toByteArray()
                        def outputStream = new FileOutputStream(file.path)
                        outputStream.write(bytes)
                        outputStream.close()
                    }
                }

                File dest = transformOutputProvider.getContentLocation(
                        directoryInput.name,
                        directoryInput.contentTypes,
                        directoryInput.scopes,
                        Format.DIRECTORY
                )

                File sourceFile = directoryInput.file
                String sourceFilePath = sourceFile.absolutePath
                String destFilePath = dest.absolutePath
                LogUtils.d(TAG, "copyDirectory sourceFilePath: $sourceFilePath , destFilePath: $destFilePath")
                FileUtils.copyDirectory(sourceFile, dest)
            }
        }

        LogUtils.d(TAG, "------------ ------------  transform 结束  ------------ ------------  ")
    }
}